#include "../TestDefinition.h"
#include "../Utils/TestUtils.h"
#include "Packet.h"
#include "SystemUtils.h"
#include "LdapLayer.h"
#include <sstream>
#include <cstring>

using pcpp_tests::utils::createPacketAndBufferFromHexResource;
using pcpp_tests::utils::createPacketFromHexResource;

PTF_TEST_CASE(LdapParsingTest)
{
	// LDAP packet
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_add_response.dat");
		pcpp::Packet ldapPacket(rawPacket1.get());

		auto ldapLayer = ldapPacket.getLayerOfType<pcpp::LdapLayer>();
		PTF_ASSERT_NOT_NULL(ldapLayer);

		PTF_ASSERT_EQUAL(ldapLayer->getMessageID(), 27);
		PTF_ASSERT_EQUAL(ldapLayer->getLdapOperationType(), pcpp::LdapOperationType::AddResponse, enum);
		PTF_ASSERT_EQUAL(ldapLayer->getProtocol(), pcpp::LDAP);
		PTF_ASSERT_EQUAL(ldapLayer->getHeaderLen(), 14);
		PTF_ASSERT_TRUE(ldapLayer->getControls().empty());
		PTF_ASSERT_EQUAL(ldapLayer->toString(), "LDAP Layer, AddResponse, Success");

		pcpp::Asn1IntegerRecord messageIdRecord(27);

		pcpp::Asn1EnumeratedRecord enumeratedRecord(0);
		pcpp::Asn1OctetStringRecord stringRecord1("");
		pcpp::Asn1OctetStringRecord stringRecord2("");
		pcpp::Asn1ConstructedRecord expectedOperationRecord(pcpp::Asn1TagClass::Application, 9,
		                                                    { &enumeratedRecord, &stringRecord1, &stringRecord2 });

		pcpp::Asn1SequenceRecord expectedRootRecord({ &messageIdRecord, &expectedOperationRecord });

		PTF_ASSERT_EQUAL(ldapLayer->getRootAsn1Record()->toString(), expectedRootRecord.toString());
		PTF_ASSERT_EQUAL(ldapLayer->getLdapOperationAsn1Record()->toString(), expectedOperationRecord.toString());
	}

	// LDAP with multiple controls
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_search_request1.dat",
		                                              pcpp_tests::utils::PacketFactory(pcpp::LINKTYPE_LINUX_SLL));
		pcpp::Packet ldapWithControlsPacket(rawPacket1.get());

		auto ldapLayer = ldapWithControlsPacket.getLayerOfType<pcpp::LdapLayer>();
		PTF_ASSERT_NOT_NULL(ldapLayer);

		auto controls = ldapLayer->getControls();
		// clang-format off
		std::vector<pcpp::LdapControl> expectedControls = {
			{ "1.2.840.113556.1.4.801", "3003020107"       },
			{ "1.2.840.113556.1.4.319", "3006020201f40400" }
		};
		// clang-format on
		PTF_ASSERT_VECTORS_EQUAL(controls, expectedControls);
	}

	// LDAP with partial controls
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_bind_request1.dat");
		pcpp::Packet ldapWithControlsPacket(rawPacket1.get());

		auto ldapLayer = ldapWithControlsPacket.getLayerOfType<pcpp::LdapLayer>();
		PTF_ASSERT_NOT_NULL(ldapLayer);

		auto controls = ldapLayer->getControls();
		std::vector<pcpp::LdapControl> expectedControls = { { "1.3.6.1.4.1.42.2.27.8.5.1" } };
		PTF_ASSERT_VECTORS_EQUAL(controls, expectedControls);
	}

	// LdapLayer tryGet
	{
		auto rawPacketAndBuf1 = createPacketAndBufferFromHexResource("PacketExamples/ldap_bind_request1.dat");
		auto& resource1 = rawPacketAndBuf1.resourceBuffer;
		auto& rawPacket1 = rawPacketAndBuf1.packet;

		// Make the underlying data buffer malformed.
		resource1.data[68] = 0x04;
		pcpp::Packet malformedLdapPacket(rawPacket1.get());

		auto malformedLdapLayer = malformedLdapPacket.getLayerOfType<pcpp::LdapLayer>();
		PTF_ASSERT_NOT_NULL(malformedLdapLayer);

		uint16_t messageId;
		PTF_ASSERT_FALSE(malformedLdapLayer->tryGet(&pcpp::LdapLayer::getMessageID, messageId));

		std::vector<pcpp::LdapControl> controls;
		PTF_ASSERT_TRUE(malformedLdapLayer->tryGet(&pcpp::LdapLayer::getControls, controls));
		std::vector<pcpp::LdapControl> expectedControls = { { "1.3.6.1.4.1.42.2.27.8.5.1" } };
		PTF_ASSERT_VECTORS_EQUAL(controls, expectedControls);
	}

	// Multiple LDAP messages in the same packet
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_multiple_messages.dat",
		                                              pcpp_tests::utils::PacketFactory(pcpp::LINKTYPE_LINUX_SLL));
		pcpp::Packet multipleLdapPacket(rawPacket1.get());

		auto ldapLayer = multipleLdapPacket.getLayerOfType<pcpp::LdapLayer>();
		PTF_ASSERT_NOT_NULL(ldapLayer);

		for (int i = 0; i < 3; i++)
		{
			PTF_ASSERT_EQUAL(ldapLayer->getLdapOperationType(), pcpp::LdapOperationType::SearchResultReference, enum);
			ldapLayer = dynamic_cast<pcpp::LdapLayer*>(ldapLayer->getNextLayer());
			PTF_ASSERT_NOT_NULL(ldapLayer);
		}

		PTF_ASSERT_EQUAL(ldapLayer->getLdapOperationType(), pcpp::LdapOperationType::SearchResultDone, enum);
		PTF_ASSERT_NULL(ldapLayer->getNextLayer());
	}

	// BindRequest with simple authentication
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_bind_request1.dat");
		pcpp::Packet bindRequestPacket(rawPacket1.get());

		auto bindRequestLayer = bindRequestPacket.getLayerOfType<pcpp::LdapBindRequestLayer>();
		PTF_ASSERT_NOT_NULL(bindRequestLayer);
		PTF_ASSERT_EQUAL(bindRequestLayer->getMessageID(), 2);
		PTF_ASSERT_EQUAL(bindRequestLayer->getLdapOperationType(), pcpp::LdapOperationType::BindRequest, enum);
		PTF_ASSERT_EQUAL(bindRequestLayer->getVersion(), 3);
		PTF_ASSERT_EQUAL(bindRequestLayer->getName(), "cn=Administrator,cn=Users,dc=cloudshark-a,dc=example,dc=com");
		PTF_ASSERT_EQUAL(bindRequestLayer->getAuthenticationType(),
		                 pcpp::LdapBindRequestLayer::AuthenticationType::Simple, enumclass);
		PTF_ASSERT_EQUAL(bindRequestLayer->getSimpleAuthentication(), "cloudshark123!");
		PTF_ASSERT_RAISES(bindRequestLayer->getSaslAuthentication(), std::invalid_argument,
		                  "Authentication type is not sasl");
		pcpp::LdapBindRequestLayer::SaslAuthentication saslAuthentication;
		PTF_ASSERT_FALSE(
		    bindRequestLayer->tryGet(&pcpp::LdapBindRequestLayer::getSaslAuthentication, saslAuthentication));
		PTF_ASSERT_EQUAL(bindRequestLayer->toString(), "LDAP Layer, BindRequest, simple");
	}

	// BindRequest with sasl authentication
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_bind_request2.dat");
		pcpp::Packet bindRequestPacket(rawPacket1.get());

		auto bindRequestLayer = bindRequestPacket.getLayerOfType<pcpp::LdapBindRequestLayer>();
		PTF_ASSERT_NOT_NULL(bindRequestLayer);
		PTF_ASSERT_EQUAL(bindRequestLayer->getMessageID(), 7);
		PTF_ASSERT_EQUAL(bindRequestLayer->getLdapOperationType(), pcpp::LdapOperationType::BindRequest, enum);
		PTF_ASSERT_EQUAL(bindRequestLayer->getVersion(), 3);
		PTF_ASSERT_EQUAL(bindRequestLayer->getName(), "");
		PTF_ASSERT_EQUAL(bindRequestLayer->getAuthenticationType(),
		                 pcpp::LdapBindRequestLayer::AuthenticationType::Sasl, enumclass);
		pcpp::LdapBindRequestLayer::SaslAuthentication expectedSaslAuthentication{
			"GSS-SPNEGO",
			{ 0x60, 0x82, 0x05, 0x1a, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02, 0xa0, 0x82, 0x05, 0x0e, 0x30,
			  0x82, 0x05, 0x0a, 0xa0, 0x24, 0x30, 0x22, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02,
			  0x02, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x06, 0x0a, 0x2b, 0x06, 0x01,
			  0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a, 0xa2, 0x82, 0x04, 0xe0, 0x04, 0x82, 0x04, 0xdc, 0x60, 0x82,
			  0x04, 0xd8, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x01, 0x00, 0x6e, 0x82,
			  0x04, 0xc7, 0x30, 0x82, 0x04, 0xc3, 0xa0, 0x03, 0x02, 0x01, 0x05, 0xa1, 0x03, 0x02, 0x01, 0x0e, 0xa2,
			  0x07, 0x03, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0xa3, 0x82, 0x03, 0xe0, 0x61, 0x82, 0x03, 0xdc, 0x30,
			  0x82, 0x03, 0xd8, 0xa0, 0x03, 0x02, 0x01, 0x05, 0xa1, 0x15, 0x1b, 0x13, 0x57, 0x32, 0x4b, 0x33, 0x2e,
			  0x56, 0x4d, 0x4e, 0x45, 0x54, 0x31, 0x2e, 0x56, 0x4d, 0x2e, 0x42, 0x41, 0x53, 0x45, 0xa2, 0x2f, 0x30,
			  0x2d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0xa1, 0x26, 0x30, 0x24, 0x1b, 0x04, 0x6c, 0x64, 0x61, 0x70, 0x1b,
			  0x1c, 0x77, 0x32, 0x6b, 0x33, 0x2d, 0x31, 0x30, 0x31, 0x2e, 0x77, 0x32, 0x6b, 0x33, 0x2e, 0x76, 0x6d,
			  0x6e, 0x65, 0x74, 0x31, 0x2e, 0x76, 0x6d, 0x2e, 0x62, 0x61, 0x73, 0x65, 0xa3, 0x82, 0x03, 0x87, 0x30,
			  0x82, 0x03, 0x83, 0xa0, 0x03, 0x02, 0x01, 0x17, 0xa1, 0x03, 0x02, 0x01, 0x07, 0xa2, 0x82, 0x03, 0x75,
			  0x04, 0x82, 0x03, 0x71, 0x6a, 0x61, 0xc8, 0x86, 0xba, 0x58, 0xd1, 0x62, 0x11, 0x3d, 0xb4, 0x26, 0x8f,
			  0x77, 0x43, 0xa1, 0x7e, 0xb4, 0x76, 0x18, 0x3b, 0xc0, 0xc5, 0x19, 0xad, 0xde, 0xa7, 0x65, 0x56, 0xa3,
			  0x70, 0x1d, 0xe3, 0x49, 0x03, 0xe6, 0xbd, 0x3f, 0x3f, 0xdc, 0xa0, 0xb0, 0x1b, 0xbc, 0xcb, 0x9a, 0x86,
			  0x93, 0xb2, 0x3f, 0xa8, 0xd1, 0x98, 0x5e, 0x14, 0x92, 0x2e, 0x4c, 0xa1, 0x9b, 0x05, 0xa9, 0x07, 0x69,
			  0x84, 0x5a, 0x58, 0x58, 0x51, 0x5b, 0xba, 0x4a, 0xf2, 0xd7, 0xe5, 0x9b, 0xfa, 0x86, 0x34, 0x28, 0x5a,
			  0x2e, 0x95, 0x4f, 0xb5, 0x18, 0x37, 0x8b, 0x8d, 0x3f, 0x27, 0x44, 0xb9, 0xbb, 0xf8, 0x84, 0x2b, 0x48,
			  0x07, 0x87, 0x9f, 0xf2, 0x8e, 0x55, 0xbf, 0xba, 0x49, 0x67, 0xe8, 0xc1, 0xd3, 0xb6, 0xc4, 0xe3, 0x58,
			  0xa5, 0x61, 0xc5, 0x4a, 0xbb, 0xc1, 0xcb, 0x7c, 0x97, 0xb6, 0x50, 0x3f, 0xe5, 0x9b, 0x7f, 0xee, 0x64,
			  0x23, 0xdf, 0xfe, 0x66, 0xfe, 0x6d, 0xcb, 0x8a, 0xf0, 0x0e, 0x69, 0xc5, 0x3d, 0x6b, 0x57, 0x6f, 0x55,
			  0x06, 0x99, 0x04, 0x38, 0x31, 0x0f, 0xb7, 0xdd, 0x14, 0x68, 0xa3, 0x2f, 0xd8, 0xe0, 0xde, 0xab, 0x40,
			  0xb1, 0x5e, 0xcf, 0xd4, 0x38, 0x56, 0x83, 0x70, 0x14, 0x0a, 0x1e, 0xda, 0xfe, 0xe7, 0x01, 0xa4, 0xa4,
			  0xb4, 0xe7, 0xb3, 0xaa, 0xef, 0xdc, 0x4b, 0x1a, 0xff, 0x58, 0x68, 0xae, 0xfe, 0x5a, 0x36, 0x29, 0x4d,
			  0x5d, 0xd6, 0x87, 0xd5, 0xa6, 0x49, 0x31, 0x43, 0xd3, 0xad, 0xe8, 0x03, 0x1c, 0x98, 0xd2, 0x8f, 0x6c,
			  0x7f, 0x3d, 0xce, 0xa4, 0x14, 0x35, 0x13, 0x2f, 0x67, 0x5f, 0x26, 0x94, 0x0d, 0x1f, 0x69, 0xe5, 0x73,
			  0xe5, 0xec, 0xe6, 0xed, 0x5a, 0x66, 0x11, 0x1f, 0xf9, 0xf4, 0xb0, 0x2a, 0x8d, 0xdd, 0x19, 0x08, 0x6e,
			  0x5b, 0x9d, 0xc0, 0xad, 0xc8, 0x6a, 0x0b, 0xc1, 0x23, 0x0f, 0x1b, 0x71, 0x5f, 0xfc, 0x40, 0x04, 0xdf,
			  0xc4, 0xa7, 0xd5, 0xf7, 0x8a, 0x4d, 0xc3, 0x1a, 0xbf, 0x83, 0x0a, 0xe6, 0xe3, 0xbf, 0xd2, 0x1c, 0x87,
			  0xfa, 0x51, 0x96, 0x54, 0x9e, 0x13, 0x0f, 0x6a, 0x08, 0x1b, 0xaf, 0xcf, 0x41, 0x70, 0xae, 0x20, 0x1c,
			  0x78, 0xa3, 0x82, 0x9a, 0x01, 0xdb, 0xa5, 0x78, 0xa2, 0xef, 0x96, 0x8f, 0x2a, 0xb6, 0x66, 0x8d, 0x81,
			  0x14, 0xdf, 0xcc, 0x65, 0xd7, 0x03, 0x8f, 0x55, 0x58, 0xbe, 0x7c, 0xdd, 0x92, 0x46, 0xd5, 0x22, 0x47,
			  0x91, 0x52, 0x60, 0xa4, 0x0e, 0x59, 0xc4, 0x8b, 0x08, 0xa1, 0xed, 0x61, 0x42, 0x7f, 0xd3, 0x03, 0x91,
			  0x7c, 0x6b, 0x34, 0xb7, 0x01, 0xa4, 0xba, 0x9a, 0x38, 0x15, 0xd4, 0x82, 0x8a, 0x22, 0x8c, 0xd2, 0x09,
			  0xda, 0x13, 0x76, 0x26, 0xe2, 0x02, 0x9a, 0xab, 0xf6, 0xc2, 0x00, 0xbf, 0x7f, 0xd6, 0x3c, 0xf6, 0xd4,
			  0x3b, 0xb6, 0x18, 0xb3, 0x1a, 0xc4, 0x8e, 0x09, 0x61, 0x35, 0x89, 0xd7, 0x4a, 0x69, 0x54, 0x2e, 0x90,
			  0x9c, 0xe0, 0xdc, 0x9c, 0x57, 0xc7, 0x7f, 0x7d, 0x89, 0xb9, 0x66, 0xde, 0x20, 0x00, 0x53, 0xa5, 0x8e,
			  0xa5, 0x8f, 0x23, 0x74, 0x51, 0x39, 0x61, 0x63, 0x8a, 0x30, 0xca, 0x49, 0xef, 0x0e, 0xec, 0x67, 0x9d,
			  0x92, 0x7e, 0x38, 0x5b, 0x5d, 0xa7, 0xd4, 0xd3, 0xc1, 0xa5, 0x91, 0x69, 0xb4, 0x63, 0x0b, 0x87, 0x4a,
			  0x1d, 0x96, 0x9e, 0x45, 0xd1, 0xfe, 0x37, 0x82, 0x08, 0x9f, 0x43, 0x85, 0x02, 0x49, 0x55, 0x09, 0x3b,
			  0x30, 0x8e, 0x19, 0x64, 0xd3, 0x07, 0x91, 0x52, 0x71, 0xaa, 0x88, 0x6c, 0x3d, 0x9b, 0x64, 0xd8, 0x46,
			  0xc8, 0x8c, 0xa1, 0x34, 0x1f, 0xd2, 0xf7, 0x2b, 0x76, 0x67, 0x9d, 0x4f, 0x25, 0x8f, 0x64, 0x7b, 0xc0,
			  0x48, 0x20, 0xe4, 0x27, 0x76, 0xc9, 0xec, 0x0d, 0x01, 0x46, 0x46, 0x52, 0x76, 0x3a, 0x49, 0xd8, 0x22,
			  0xc9, 0xd2, 0x5b, 0x60, 0x39, 0x03, 0xeb, 0xd6, 0x33, 0x89, 0x52, 0x25, 0x9b, 0x83, 0xa7, 0x40, 0xa4,
			  0x20, 0xd6, 0x9d, 0x23, 0xae, 0xbb, 0xdf, 0x06, 0xa9, 0x2d, 0x88, 0xa4, 0x6f, 0xfc, 0xd8, 0xd8, 0x1a,
			  0x47, 0xb6, 0xec, 0x99, 0xb6, 0xce, 0xa0, 0x48, 0x9c, 0xc8, 0x3e, 0xf1, 0x57, 0x57, 0xc4, 0x05, 0x3d,
			  0x53, 0x84, 0x46, 0xf2, 0xe6, 0xb9, 0xeb, 0xa1, 0x2c, 0xe4, 0x96, 0x9b, 0x8d, 0x6d, 0xf9, 0xb3, 0xef,
			  0x57, 0x4b, 0x7d, 0x40, 0x13, 0x41, 0xc2, 0xf5, 0x55, 0xa0, 0x0f, 0x02, 0x91, 0x64, 0xe5, 0xd3, 0x87,
			  0x28, 0x2c, 0x0c, 0x87, 0x91, 0xba, 0x8c, 0x69, 0x81, 0x62, 0x48, 0xe2, 0xe5, 0x44, 0xa9, 0xc1, 0x2b,
			  0x7a, 0xeb, 0xa6, 0x29, 0xfd, 0xee, 0xa2, 0xe1, 0x11, 0x65, 0x5e, 0x44, 0xb9, 0xc2, 0x15, 0x92, 0x4c,
			  0x54, 0x55, 0xea, 0xa4, 0xab, 0x32, 0xae, 0xa1, 0xd9, 0xce, 0xf1, 0xd8, 0x6e, 0x8a, 0xcf, 0x6b, 0x0f,
			  0xf4, 0xdc, 0xab, 0xaf, 0x4f, 0x0e, 0x2d, 0x9a, 0xe6, 0x5c, 0x8b, 0xb1, 0x06, 0x5e, 0x04, 0x18, 0xff,
			  0x12, 0xd4, 0x62, 0x69, 0x30, 0x31, 0x59, 0x38, 0xbf, 0xe0, 0x0a, 0x8d, 0x03, 0xe8, 0xe7, 0x0e, 0x9d,
			  0xea, 0x9d, 0xc9, 0xff, 0x74, 0x85, 0x4c, 0xbb, 0x4d, 0xbd, 0xf7, 0x00, 0xa6, 0x2e, 0x77, 0xb2, 0x6e,
			  0x50, 0xb1, 0x3e, 0x2d, 0x39, 0x60, 0xc9, 0x13, 0x36, 0x0c, 0x84, 0xc8, 0x7e, 0x80, 0x1e, 0xd3, 0xdf,
			  0x3d, 0xb0, 0xe2, 0x76, 0x04, 0x50, 0x8c, 0xb7, 0x30, 0xc5, 0xa0, 0x52, 0xc0, 0x68, 0xab, 0xe5, 0x82,
			  0x6b, 0x01, 0xbe, 0x9f, 0x62, 0xe3, 0x3b, 0x9a, 0xf8, 0xed, 0xb6, 0x66, 0x7c, 0x57, 0xcb, 0x1a, 0xa8,
			  0x79, 0x74, 0x3b, 0x77, 0xa7, 0x43, 0x2f, 0x75, 0xfe, 0x3a, 0xe2, 0x11, 0xf9, 0x6a, 0xf4, 0x1a, 0xde,
			  0xf1, 0xe1, 0xc5, 0x07, 0x25, 0x6f, 0xe5, 0xfa, 0x2b, 0xcc, 0xab, 0xe5, 0x2c, 0xf8, 0x21, 0x6d, 0x34,
			  0x10, 0xe6, 0x37, 0x85, 0x06, 0xd4, 0x27, 0x34, 0x34, 0x58, 0x33, 0x2d, 0x15, 0x3a, 0x77, 0xa1, 0x62,
			  0xc4, 0xc5, 0xf1, 0x8d, 0x9f, 0x31, 0xb0, 0xc1, 0x42, 0x88, 0x0c, 0xad, 0x22, 0x29, 0x98, 0x17, 0x20,
			  0x61, 0x5a, 0xb2, 0x6b, 0x7c, 0x13, 0x44, 0x2e, 0x43, 0x17, 0x8a, 0xad, 0xee, 0x43, 0x65, 0x10, 0xc9,
			  0x1b, 0xc9, 0xd5, 0xd7, 0x35, 0xeb, 0x94, 0x53, 0xcf, 0x39, 0xce, 0xf5, 0x12, 0x0e, 0x28, 0x60, 0x37,
			  0x75, 0xf0, 0x48, 0x3f, 0x01, 0xc3, 0xc4, 0x8b, 0x5b, 0x06, 0x0c, 0xa7, 0xf3, 0xa5, 0x4d, 0x7c, 0x7c,
			  0x99, 0xa4, 0x81, 0xc9, 0x30, 0x81, 0xc6, 0xa0, 0x03, 0x02, 0x01, 0x17, 0xa2, 0x81, 0xbe, 0x04, 0x81,
			  0xbb, 0x03, 0xab, 0x65, 0x67, 0x60, 0xa3, 0x51, 0x2f, 0xec, 0xc7, 0x03, 0x2d, 0xa8, 0xb2, 0x01, 0x46,
			  0x59, 0xf0, 0xfb, 0x34, 0xeb, 0x76, 0xb4, 0x61, 0xe4, 0x04, 0x4d, 0xa2, 0x4d, 0x16, 0xd4, 0x58, 0xe3,
			  0xe1, 0xc5, 0x89, 0x19, 0xc7, 0x4c, 0x4c, 0x07, 0x20, 0xaa, 0xfb, 0x87, 0xa9, 0x48, 0x15, 0x23, 0x72,
			  0xa2, 0x48, 0x3a, 0x4d, 0x1a, 0xe9, 0xb9, 0x5b, 0x85, 0x8a, 0x52, 0xab, 0xaa, 0x94, 0xe7, 0xaa, 0x64,
			  0x1a, 0x8b, 0x99, 0x7d, 0x7e, 0x6c, 0x6e, 0x57, 0x0b, 0x59, 0x08, 0xcc, 0x54, 0x91, 0x55, 0xf5, 0xe6,
			  0xf1, 0x10, 0xc9, 0x8d, 0x64, 0x89, 0x78, 0x72, 0x7a, 0xba, 0xe3, 0x92, 0x1d, 0xa5, 0x2a, 0x4c, 0x1f,
			  0xd7, 0x6b, 0xeb, 0x12, 0x1b, 0xf3, 0x39, 0x6b, 0xe8, 0xf9, 0x8e, 0x4a, 0xcf, 0x1e, 0xbf, 0xc3, 0xb6,
			  0xfb, 0x7a, 0x13, 0x54, 0xc1, 0x21, 0x87, 0x3e, 0x59, 0x18, 0x5d, 0xb9, 0x00, 0x30, 0x08, 0x4d, 0x97,
			  0x86, 0x47, 0x98, 0xd7, 0x9e, 0xb9, 0xdf, 0x30, 0x75, 0x6c, 0xa1, 0xfa, 0xa7, 0xa8, 0x08, 0x80, 0xf7,
			  0x4f, 0x7d, 0x93, 0x64, 0x2d, 0x9c, 0xeb, 0x5e, 0x01, 0x28, 0xce, 0xd6, 0xab, 0x09, 0x6a, 0x4f, 0x01,
			  0x5e, 0x5a, 0x03, 0x2b, 0x42, 0x70, 0x23, 0x1e, 0x7f, 0xf1, 0xbc, 0xd0, 0x87, 0xe8, 0xb5, 0x27, 0x02,
			  0x7d }
		};
		PTF_ASSERT_EQUAL(bindRequestLayer->getSaslAuthentication(), expectedSaslAuthentication);
		PTF_ASSERT_RAISES(bindRequestLayer->getSimpleAuthentication(), std::invalid_argument,
		                  "Authentication type is not simple");
		std::string simpleAuthentication;
		PTF_ASSERT_FALSE(
		    bindRequestLayer->tryGet(&pcpp::LdapBindRequestLayer::getSimpleAuthentication, simpleAuthentication));
		PTF_ASSERT_EQUAL(bindRequestLayer->toString(), "LDAP Layer, BindRequest, sasl");
	}

	// BindResponse with server sals credentials
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_bind_response1.dat");
		pcpp::Packet bindResponsePacket(rawPacket1.get());

		auto bindResponseLayer = bindResponsePacket.getLayerOfType<pcpp::LdapBindResponseLayer>();
		PTF_ASSERT_NOT_NULL(bindResponseLayer);
		PTF_ASSERT_EQUAL(bindResponseLayer->getMessageID(), 215);
		PTF_ASSERT_EQUAL(bindResponseLayer->getLdapOperationType(), pcpp::LdapOperationType::BindResponse, enum);
		PTF_ASSERT_EQUAL(bindResponseLayer->getResultCode(), pcpp::LdapResultCode::Success, enum);
		PTF_ASSERT_EQUAL(bindResponseLayer->getMatchedDN(), "");
		PTF_ASSERT_EQUAL(bindResponseLayer->getDiagnosticMessage(), "");
		PTF_ASSERT_VECTORS_EQUAL(bindResponseLayer->getReferral(), std::vector<std::string>());
		std::vector<uint8_t> expectedServerSaslCredentials = {
			0xa1, 0x81, 0xa1, 0x30, 0x81, 0x9e, 0xa0, 0x03, 0x0a, 0x01, 0x00, 0xa1, 0x0b, 0x06, 0x09, 0x2a, 0x86,
			0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02, 0xa2, 0x81, 0x89, 0x04, 0x81, 0x86, 0x60, 0x81, 0x83, 0x06,
			0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x02, 0x00, 0x6f, 0x74, 0x30, 0x72, 0xa0,
			0x03, 0x02, 0x01, 0x05, 0xa1, 0x03, 0x02, 0x01, 0x0f, 0xa2, 0x66, 0x30, 0x64, 0xa0, 0x03, 0x02, 0x01,
			0x17, 0xa2, 0x5d, 0x04, 0x5b, 0x4a, 0x9f, 0x10, 0xab, 0x89, 0x96, 0xfa, 0x43, 0xf2, 0xfb, 0x40, 0x92,
			0xa7, 0x6c, 0xc3, 0xfa, 0x6c, 0x1f, 0x00, 0x11, 0x67, 0xfa, 0xc9, 0x04, 0xda, 0xb0, 0x67, 0xf5, 0xf2,
			0xda, 0x59, 0xa7, 0x54, 0x90, 0x57, 0xbd, 0x3e, 0xb4, 0x6c, 0xb4, 0x67, 0xfd, 0x3b, 0x01, 0xd7, 0x3f,
			0x50, 0x51, 0xaa, 0x63, 0x2e, 0xd8, 0xd6, 0xa6, 0xe5, 0x81, 0xbb, 0xab, 0x17, 0x80, 0xfa, 0xab, 0xac,
			0x51, 0x52, 0x84, 0x13, 0x9c, 0xfb, 0x44, 0xc2, 0x04, 0xae, 0x1e, 0xc2, 0x5a, 0x2d, 0x58, 0x90, 0x9d,
			0x22, 0xff, 0x52, 0x34, 0x9e, 0x6d, 0x2e, 0x4d, 0x83, 0x5b, 0x98
		};
		PTF_ASSERT_VECTORS_EQUAL(bindResponseLayer->getServerSaslCredentials(), expectedServerSaslCredentials);
	}

	// BindResponse without server sals credentials
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_bind_response2.dat");
		pcpp::Packet bindResponsePacket(rawPacket1.get());

		auto bindResponseLayer = bindResponsePacket.getLayerOfType<pcpp::LdapBindResponseLayer>();
		PTF_ASSERT_NOT_NULL(bindResponseLayer);
		PTF_ASSERT_EQUAL(bindResponseLayer->getMessageID(), 2);
		PTF_ASSERT_EQUAL(bindResponseLayer->getLdapOperationType(), pcpp::LdapOperationType::BindResponse, enum);
		PTF_ASSERT_EQUAL(bindResponseLayer->getResultCode(), pcpp::LdapResultCode::Success, enum);
		PTF_ASSERT_EQUAL(bindResponseLayer->getMatchedDN(), "");
		PTF_ASSERT_EQUAL(bindResponseLayer->getDiagnosticMessage(), "");
		PTF_ASSERT_VECTORS_EQUAL(bindResponseLayer->getReferral(), std::vector<std::string>());
		PTF_ASSERT_VECTORS_EQUAL(bindResponseLayer->getServerSaslCredentials(), std::vector<uint8_t>());
	}

	// UnbindRequest
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_unbind_request.dat");
		pcpp::Packet unbindRequestPacket(rawPacket1.get());

		auto unbindRequestLayer = unbindRequestPacket.getLayerOfType<pcpp::LdapUnbindRequestLayer>();
		PTF_ASSERT_NOT_NULL(unbindRequestLayer);
		PTF_ASSERT_EQUAL(unbindRequestLayer->getMessageID(), 3);
		PTF_ASSERT_EQUAL(unbindRequestLayer->getLdapOperationType(), pcpp::LdapOperationType::UnbindRequest, enum);
		PTF_ASSERT_EQUAL(unbindRequestLayer->toString(), "LDAP Layer, UnbindRequest");
	}

	// SearchRequest
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_search_request2.dat");
		pcpp::Packet searchRequestPacket(rawPacket1.get());

		auto searchRequestLayer = searchRequestPacket.getLayerOfType<pcpp::LdapSearchRequestLayer>();
		PTF_ASSERT_NOT_NULL(searchRequestLayer);
		PTF_ASSERT_EQUAL(searchRequestLayer->getMessageID(), 9);
		PTF_ASSERT_EQUAL(searchRequestLayer->getLdapOperationType(), pcpp::LdapOperationType::SearchRequest, enum);
		PTF_ASSERT_EQUAL(searchRequestLayer->getBaseObject(), "cn=schema");
		PTF_ASSERT_EQUAL(searchRequestLayer->getScope(), pcpp::LdapSearchRequestLayer::SearchRequestScope::BaseObject,
		                 enum);
		PTF_ASSERT_EQUAL(searchRequestLayer->getDerefAlias(), pcpp::LdapSearchRequestLayer::DerefAliases::DerefAlways,
		                 enum);
		PTF_ASSERT_EQUAL(searchRequestLayer->getSizeLimit(), 0);
		PTF_ASSERT_EQUAL(searchRequestLayer->getTimeLimit(), 0);
		PTF_ASSERT_FALSE(searchRequestLayer->getTypesOnly());
		std::ostringstream expectedFilter;
		expectedFilter << "ContextSpecific (3) (constructed), Length: 2+24" << std::endl
		               << "  OctetString, Length: 2+11, Value: objectClass" << std::endl
		               << "  OctetString, Length: 2+9, Value: subschema";
		PTF_ASSERT_EQUAL(searchRequestLayer->getFilter()->toString(), expectedFilter.str());
		PTF_ASSERT_EQUAL(searchRequestLayer->toString(), "LDAP Layer, SearchRequest, \"cn=schema\", BaseObject");
		auto attributes = searchRequestLayer->getAttributes();
		std::vector<std::string> expectedAttributes = { "objectClasses",
			                                            "attributeTypes",
			                                            "ldapSyntaxes",
			                                            "matchingRules",
			                                            "matchingRuleUse",
			                                            "dITContentRules",
			                                            "dITStructureRules",
			                                            "nameForms",
			                                            "createTimestamp",
			                                            "modifyTimestamp",
			                                            "*",
			                                            "+" };
		PTF_ASSERT_VECTORS_EQUAL(attributes, expectedAttributes);
	}

	// SearchResultEntry
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_search_result_entry.dat");
		pcpp::Packet searchResEntryPacket(rawPacket1.get());

		auto searchResultEntryLayer = searchResEntryPacket.getLayerOfType<pcpp::LdapSearchResultEntryLayer>();
		PTF_ASSERT_NOT_NULL(searchResultEntryLayer);
		PTF_ASSERT_EQUAL(searchResultEntryLayer->getMessageID(), 16);
		PTF_ASSERT_EQUAL(searchResultEntryLayer->getLdapOperationType(), pcpp::LdapOperationType::SearchResultEntry,
		                 enum);
		PTF_ASSERT_EQUAL(searchResultEntryLayer->getObjectName(),
		                 "cn=b.smith,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org");
		// clang-format off
		std::vector<pcpp::LdapAttribute> expectedAttributes = {
			{ "objectclass", { "inetOrgPerson", "organizationalPerson", "person", "top" } },
			{ "sn",          { "Young" }                                                },
			{ "cn",          { "b.smith" }                                              },
			{ "givenname",   { "Beatrix" }                                              }
		};
		// clang-format on
		PTF_ASSERT_VECTORS_EQUAL(searchResultEntryLayer->getAttributes(), expectedAttributes);
	}

	// LdapSearchResultDoneLayer
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_search_result_done.dat");
		pcpp::Packet searchResultDonePacket(rawPacket1.get());

		auto searchResultDoneLayer = searchResultDonePacket.getLayerOfType<pcpp::LdapSearchResultDoneLayer>();
		PTF_ASSERT_NOT_NULL(searchResultDoneLayer);
		PTF_ASSERT_EQUAL(searchResultDoneLayer->getMessageID(), 8);
		PTF_ASSERT_EQUAL(searchResultDoneLayer->getLdapOperationType(), pcpp::LdapOperationType::SearchResultDone,
		                 enum);
		PTF_ASSERT_EQUAL(searchResultDoneLayer->getResultCode(), pcpp::LdapResultCode::Success, enum);
		PTF_ASSERT_EQUAL(searchResultDoneLayer->getMatchedDN(), "");
		PTF_ASSERT_EQUAL(searchResultDoneLayer->getDiagnosticMessage(), "");
		PTF_ASSERT_VECTORS_EQUAL(searchResultDoneLayer->getReferral(), std::vector<std::string>());
		PTF_ASSERT_EQUAL(searchResultDoneLayer->toString(), "LDAP Layer, SearchResultDone, Success");
	}

	// LdapModifyResponseLayer
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_modify_response.dat");
		pcpp::Packet modifyResponsePacket(rawPacket1.get());

		auto modifyResponseLayer = modifyResponsePacket.getLayerOfType<pcpp::LdapModifyResponseLayer>();
		PTF_ASSERT_NOT_NULL(modifyResponseLayer);
		PTF_ASSERT_EQUAL(modifyResponseLayer->getMessageID(), 14);
		PTF_ASSERT_EQUAL(modifyResponseLayer->getLdapOperationType(), pcpp::LdapOperationType::ModifyResponse, enum);
		PTF_ASSERT_EQUAL(modifyResponseLayer->getResultCode(), pcpp::LdapResultCode::NoSuchObject, enum);
		PTF_ASSERT_EQUAL(modifyResponseLayer->getMatchedDN(), "");
		PTF_ASSERT_EQUAL(modifyResponseLayer->getDiagnosticMessage(), "");
		PTF_ASSERT_VECTORS_EQUAL(modifyResponseLayer->getReferral(), std::vector<std::string>());
		PTF_ASSERT_EQUAL(modifyResponseLayer->toString(), "LDAP Layer, ModifyResponse, NoSuchObject");
	}

	// LdapAddResponseLayer
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_add_response.dat");
		pcpp::Packet addResponsePacket(rawPacket1.get());

		auto addResponseLayer = addResponsePacket.getLayerOfType<pcpp::LdapAddResponseLayer>();
		PTF_ASSERT_NOT_NULL(addResponseLayer);
		PTF_ASSERT_EQUAL(addResponseLayer->getMessageID(), 27);
		PTF_ASSERT_EQUAL(addResponseLayer->getLdapOperationType(), pcpp::LdapOperationType::AddResponse, enum);
		PTF_ASSERT_EQUAL(addResponseLayer->getResultCode(), pcpp::LdapResultCode::Success, enum);
		PTF_ASSERT_EQUAL(addResponseLayer->getMatchedDN(), "");
		PTF_ASSERT_EQUAL(addResponseLayer->getDiagnosticMessage(), "");
		PTF_ASSERT_VECTORS_EQUAL(addResponseLayer->getReferral(), std::vector<std::string>());
		PTF_ASSERT_EQUAL(addResponseLayer->toString(), "LDAP Layer, AddResponse, Success");
	}

	// LdapDeleteResponseLayer
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_delete_response.dat");
		pcpp::Packet deleteResponsePacket(rawPacket1.get());

		auto deleteResponseLayer = deleteResponsePacket.getLayerOfType<pcpp::LdapDeleteResponseLayer>();
		PTF_ASSERT_NOT_NULL(deleteResponseLayer);
		PTF_ASSERT_EQUAL(deleteResponseLayer->getMessageID(), 27);
		PTF_ASSERT_EQUAL(deleteResponseLayer->getLdapOperationType(), pcpp::LdapOperationType::DeleteResponse, enum);
		PTF_ASSERT_EQUAL(deleteResponseLayer->getResultCode(), pcpp::LdapResultCode::NoSuchObject, enum);
		PTF_ASSERT_EQUAL(deleteResponseLayer->getMatchedDN(), "ou=People,dc=example,dc=com");
		PTF_ASSERT_EQUAL(deleteResponseLayer->getDiagnosticMessage(), "LDAP: error code 32 - No such object");

		std::vector<std::string> expectedReferral = { "ldap://ldap.example.com/dc=example,dc=com",
			                                          "ldap://ldap.example.com/dc=example,dc=com?objectClass?one" };
		PTF_ASSERT_VECTORS_EQUAL(deleteResponseLayer->getReferral(), expectedReferral);
		PTF_ASSERT_EQUAL(deleteResponseLayer->toString(), "LDAP Layer, DeleteResponse, NoSuchObject");
	}

	// LdapModifyDNResponseLayer
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_modify_dn_response.dat");
		pcpp::Packet modifyDNResponsePacket(rawPacket1.get());

		auto modifyDNResponseLayer = modifyDNResponsePacket.getLayerOfType<pcpp::LdapModifyDNResponseLayer>();
		PTF_ASSERT_NOT_NULL(modifyDNResponseLayer);
		PTF_ASSERT_EQUAL(modifyDNResponseLayer->getMessageID(), 15);
		PTF_ASSERT_EQUAL(modifyDNResponseLayer->getLdapOperationType(), pcpp::LdapOperationType::ModifyDNResponse,
		                 enum);
		PTF_ASSERT_EQUAL(modifyDNResponseLayer->getResultCode(), pcpp::LdapResultCode::NoSuchObject, enum);
		PTF_ASSERT_EQUAL(modifyDNResponseLayer->getMatchedDN(), "ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org");
		PTF_ASSERT_EQUAL(modifyDNResponseLayer->getDiagnosticMessage(), "");
		PTF_ASSERT_VECTORS_EQUAL(modifyDNResponseLayer->getReferral(), std::vector<std::string>());
		PTF_ASSERT_EQUAL(modifyDNResponseLayer->toString(), "LDAP Layer, ModifyDNResponse, NoSuchObject");
	}

	// LdapCompareResponseLayer
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_compare_response.dat");
		pcpp::Packet compareResponsePacket(rawPacket1.get());

		auto compareResponseLayer = compareResponsePacket.getLayerOfType<pcpp::LdapCompareResponseLayer>();
		PTF_ASSERT_NOT_NULL(compareResponseLayer);
		PTF_ASSERT_EQUAL(compareResponseLayer->getMessageID(), 28);
		PTF_ASSERT_EQUAL(compareResponseLayer->getLdapOperationType(), pcpp::LdapOperationType::CompareResponse, enum);
		PTF_ASSERT_EQUAL(compareResponseLayer->getResultCode(), pcpp::LdapResultCode::CompareFalse, enum);
		PTF_ASSERT_EQUAL(compareResponseLayer->getMatchedDN(), "");
		PTF_ASSERT_EQUAL(compareResponseLayer->getDiagnosticMessage(), "");
		PTF_ASSERT_VECTORS_EQUAL(compareResponseLayer->getReferral(), std::vector<std::string>());
		PTF_ASSERT_EQUAL(compareResponseLayer->toString(), "LDAP Layer, CompareResponse, CompareFalse");
	}
}  // LdapParsingTest

PTF_TEST_CASE(LdapCreationTest)
{
	// LDAP packet with multiple controls
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_search_request1.dat",
		                                              pcpp_tests::utils::PacketFactory(pcpp::LINKTYPE_LINUX_SLL));
		pcpp::Packet ldapPacket(rawPacket1.get());

		pcpp::Asn1OctetStringRecord stringRecord("DC=matrix,DC=local");
		pcpp::Asn1EnumeratedRecord enumeratedRecord1(2);
		pcpp::Asn1EnumeratedRecord enumeratedRecord2(3);
		pcpp::Asn1IntegerRecord integerRecord1(0);
		pcpp::Asn1IntegerRecord integerRecord2(0);
		pcpp::Asn1BooleanRecord booleanRecord(false);

		pcpp::Asn1GenericRecord subRecord1(pcpp::Asn1TagClass::ContextSpecific, false, 1,
		                                   "2.16.840.1.113730.3.3.2.46.1");
		pcpp::Asn1GenericRecord subRecord2(pcpp::Asn1TagClass::ContextSpecific, false, 2, "departmentNumber");
		pcpp::Asn1GenericRecord subRecord3(pcpp::Asn1TagClass::ContextSpecific, false, 3, ">=N4709");
		pcpp::Asn1ConstructedRecord constructedRecord1(pcpp::Asn1TagClass::ContextSpecific, 9,
		                                               { &subRecord1, &subRecord2, &subRecord3 });

		pcpp::Asn1OctetStringRecord stringSubRecord1("*");
		pcpp::Asn1OctetStringRecord stringSubRecord2("ntsecuritydescriptor");
		pcpp::Asn1SequenceRecord sequenceRecord({ &stringSubRecord1, &stringSubRecord2 });

		// clang-format off
		std::vector<pcpp::LdapControl> controls = {
			{ "1.2.840.113556.1.4.801", "3003020107"       },
			{ "1.2.840.113556.1.4.319", "3006020201f40400" }
		};
		// clang-format on

		pcpp::LdapLayer ldapLayer(6, pcpp::LdapOperationType::SearchRequest,
		                          { &stringRecord, &enumeratedRecord1, &enumeratedRecord2, &integerRecord1,
		                            &integerRecord2, &booleanRecord, &constructedRecord1, &sequenceRecord },
		                          controls);

		auto expectedLdapLayer = ldapPacket.getLayerOfType<pcpp::LdapLayer>();
		PTF_ASSERT_NOT_NULL(expectedLdapLayer);

		PTF_ASSERT_BUF_COMPARE(ldapLayer.getData(), expectedLdapLayer->getData(), expectedLdapLayer->getDataLen());
	}

	// LDAP packet with partial controls
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_bind_request1.dat");
		pcpp::Packet ldapPacket(rawPacket1.get());

		pcpp::Asn1IntegerRecord integerRecord(3);
		pcpp::Asn1OctetStringRecord stringRecord("cn=Administrator,cn=Users,dc=cloudshark-a,dc=example,dc=com");
		uint8_t contextSpecificData[14] = { 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x68,
			                                0x61, 0x72, 0x6b, 0x31, 0x32, 0x33, 0x21 };
		pcpp::Asn1GenericRecord contextSpecificRecord(pcpp::Asn1TagClass::ContextSpecific, false, 0,
		                                              contextSpecificData, 14);
		std::vector<pcpp::LdapControl> controls = { { "1.3.6.1.4.1.42.2.27.8.5.1" } };

		pcpp::LdapLayer ldapLayer(2, pcpp::LdapOperationType::BindRequest,
		                          { &integerRecord, &stringRecord, &contextSpecificRecord }, controls);

		auto expectedLdapLayer = ldapPacket.getLayerOfType<pcpp::LdapLayer>();
		PTF_ASSERT_NOT_NULL(expectedLdapLayer);

		PTF_ASSERT_BUF_COMPARE(ldapLayer.getData(), expectedLdapLayer->getData(), expectedLdapLayer->getDataLen());
	}

	// BindRequest with simple authentication
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_bind_request1.dat");
		pcpp::Packet bindRequestPacket(rawPacket1.get());

		pcpp::LdapBindRequestLayer bindRequestLayer(2, 3, "cn=Administrator,cn=Users,dc=cloudshark-a,dc=example,dc=com",
		                                            "cloudshark123!", { { "1.3.6.1.4.1.42.2.27.8.5.1" } });

		auto expectedBindRequestLayer = bindRequestPacket.getLayerOfType<pcpp::LdapBindRequestLayer>();
		PTF_ASSERT_NOT_NULL(expectedBindRequestLayer);

		PTF_ASSERT_BUF_COMPARE(bindRequestLayer.getData(), expectedBindRequestLayer->getData(),
		                       expectedBindRequestLayer->getDataLen());
	}

	// BindRequest with sasl authentication
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_bind_request2.dat");
		pcpp::Packet bindRequestPacket(rawPacket1.get());

		pcpp::LdapBindRequestLayer::SaslAuthentication saslAuthentication{
			"GSS-SPNEGO",
			{ 0x60, 0x82, 0x05, 0x1a, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02, 0xa0, 0x82, 0x05, 0x0e, 0x30,
			  0x82, 0x05, 0x0a, 0xa0, 0x24, 0x30, 0x22, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02,
			  0x02, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x06, 0x0a, 0x2b, 0x06, 0x01,
			  0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a, 0xa2, 0x82, 0x04, 0xe0, 0x04, 0x82, 0x04, 0xdc, 0x60, 0x82,
			  0x04, 0xd8, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x01, 0x00, 0x6e, 0x82,
			  0x04, 0xc7, 0x30, 0x82, 0x04, 0xc3, 0xa0, 0x03, 0x02, 0x01, 0x05, 0xa1, 0x03, 0x02, 0x01, 0x0e, 0xa2,
			  0x07, 0x03, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0xa3, 0x82, 0x03, 0xe0, 0x61, 0x82, 0x03, 0xdc, 0x30,
			  0x82, 0x03, 0xd8, 0xa0, 0x03, 0x02, 0x01, 0x05, 0xa1, 0x15, 0x1b, 0x13, 0x57, 0x32, 0x4b, 0x33, 0x2e,
			  0x56, 0x4d, 0x4e, 0x45, 0x54, 0x31, 0x2e, 0x56, 0x4d, 0x2e, 0x42, 0x41, 0x53, 0x45, 0xa2, 0x2f, 0x30,
			  0x2d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0xa1, 0x26, 0x30, 0x24, 0x1b, 0x04, 0x6c, 0x64, 0x61, 0x70, 0x1b,
			  0x1c, 0x77, 0x32, 0x6b, 0x33, 0x2d, 0x31, 0x30, 0x31, 0x2e, 0x77, 0x32, 0x6b, 0x33, 0x2e, 0x76, 0x6d,
			  0x6e, 0x65, 0x74, 0x31, 0x2e, 0x76, 0x6d, 0x2e, 0x62, 0x61, 0x73, 0x65, 0xa3, 0x82, 0x03, 0x87, 0x30,
			  0x82, 0x03, 0x83, 0xa0, 0x03, 0x02, 0x01, 0x17, 0xa1, 0x03, 0x02, 0x01, 0x07, 0xa2, 0x82, 0x03, 0x75,
			  0x04, 0x82, 0x03, 0x71, 0x6a, 0x61, 0xc8, 0x86, 0xba, 0x58, 0xd1, 0x62, 0x11, 0x3d, 0xb4, 0x26, 0x8f,
			  0x77, 0x43, 0xa1, 0x7e, 0xb4, 0x76, 0x18, 0x3b, 0xc0, 0xc5, 0x19, 0xad, 0xde, 0xa7, 0x65, 0x56, 0xa3,
			  0x70, 0x1d, 0xe3, 0x49, 0x03, 0xe6, 0xbd, 0x3f, 0x3f, 0xdc, 0xa0, 0xb0, 0x1b, 0xbc, 0xcb, 0x9a, 0x86,
			  0x93, 0xb2, 0x3f, 0xa8, 0xd1, 0x98, 0x5e, 0x14, 0x92, 0x2e, 0x4c, 0xa1, 0x9b, 0x05, 0xa9, 0x07, 0x69,
			  0x84, 0x5a, 0x58, 0x58, 0x51, 0x5b, 0xba, 0x4a, 0xf2, 0xd7, 0xe5, 0x9b, 0xfa, 0x86, 0x34, 0x28, 0x5a,
			  0x2e, 0x95, 0x4f, 0xb5, 0x18, 0x37, 0x8b, 0x8d, 0x3f, 0x27, 0x44, 0xb9, 0xbb, 0xf8, 0x84, 0x2b, 0x48,
			  0x07, 0x87, 0x9f, 0xf2, 0x8e, 0x55, 0xbf, 0xba, 0x49, 0x67, 0xe8, 0xc1, 0xd3, 0xb6, 0xc4, 0xe3, 0x58,
			  0xa5, 0x61, 0xc5, 0x4a, 0xbb, 0xc1, 0xcb, 0x7c, 0x97, 0xb6, 0x50, 0x3f, 0xe5, 0x9b, 0x7f, 0xee, 0x64,
			  0x23, 0xdf, 0xfe, 0x66, 0xfe, 0x6d, 0xcb, 0x8a, 0xf0, 0x0e, 0x69, 0xc5, 0x3d, 0x6b, 0x57, 0x6f, 0x55,
			  0x06, 0x99, 0x04, 0x38, 0x31, 0x0f, 0xb7, 0xdd, 0x14, 0x68, 0xa3, 0x2f, 0xd8, 0xe0, 0xde, 0xab, 0x40,
			  0xb1, 0x5e, 0xcf, 0xd4, 0x38, 0x56, 0x83, 0x70, 0x14, 0x0a, 0x1e, 0xda, 0xfe, 0xe7, 0x01, 0xa4, 0xa4,
			  0xb4, 0xe7, 0xb3, 0xaa, 0xef, 0xdc, 0x4b, 0x1a, 0xff, 0x58, 0x68, 0xae, 0xfe, 0x5a, 0x36, 0x29, 0x4d,
			  0x5d, 0xd6, 0x87, 0xd5, 0xa6, 0x49, 0x31, 0x43, 0xd3, 0xad, 0xe8, 0x03, 0x1c, 0x98, 0xd2, 0x8f, 0x6c,
			  0x7f, 0x3d, 0xce, 0xa4, 0x14, 0x35, 0x13, 0x2f, 0x67, 0x5f, 0x26, 0x94, 0x0d, 0x1f, 0x69, 0xe5, 0x73,
			  0xe5, 0xec, 0xe6, 0xed, 0x5a, 0x66, 0x11, 0x1f, 0xf9, 0xf4, 0xb0, 0x2a, 0x8d, 0xdd, 0x19, 0x08, 0x6e,
			  0x5b, 0x9d, 0xc0, 0xad, 0xc8, 0x6a, 0x0b, 0xc1, 0x23, 0x0f, 0x1b, 0x71, 0x5f, 0xfc, 0x40, 0x04, 0xdf,
			  0xc4, 0xa7, 0xd5, 0xf7, 0x8a, 0x4d, 0xc3, 0x1a, 0xbf, 0x83, 0x0a, 0xe6, 0xe3, 0xbf, 0xd2, 0x1c, 0x87,
			  0xfa, 0x51, 0x96, 0x54, 0x9e, 0x13, 0x0f, 0x6a, 0x08, 0x1b, 0xaf, 0xcf, 0x41, 0x70, 0xae, 0x20, 0x1c,
			  0x78, 0xa3, 0x82, 0x9a, 0x01, 0xdb, 0xa5, 0x78, 0xa2, 0xef, 0x96, 0x8f, 0x2a, 0xb6, 0x66, 0x8d, 0x81,
			  0x14, 0xdf, 0xcc, 0x65, 0xd7, 0x03, 0x8f, 0x55, 0x58, 0xbe, 0x7c, 0xdd, 0x92, 0x46, 0xd5, 0x22, 0x47,
			  0x91, 0x52, 0x60, 0xa4, 0x0e, 0x59, 0xc4, 0x8b, 0x08, 0xa1, 0xed, 0x61, 0x42, 0x7f, 0xd3, 0x03, 0x91,
			  0x7c, 0x6b, 0x34, 0xb7, 0x01, 0xa4, 0xba, 0x9a, 0x38, 0x15, 0xd4, 0x82, 0x8a, 0x22, 0x8c, 0xd2, 0x09,
			  0xda, 0x13, 0x76, 0x26, 0xe2, 0x02, 0x9a, 0xab, 0xf6, 0xc2, 0x00, 0xbf, 0x7f, 0xd6, 0x3c, 0xf6, 0xd4,
			  0x3b, 0xb6, 0x18, 0xb3, 0x1a, 0xc4, 0x8e, 0x09, 0x61, 0x35, 0x89, 0xd7, 0x4a, 0x69, 0x54, 0x2e, 0x90,
			  0x9c, 0xe0, 0xdc, 0x9c, 0x57, 0xc7, 0x7f, 0x7d, 0x89, 0xb9, 0x66, 0xde, 0x20, 0x00, 0x53, 0xa5, 0x8e,
			  0xa5, 0x8f, 0x23, 0x74, 0x51, 0x39, 0x61, 0x63, 0x8a, 0x30, 0xca, 0x49, 0xef, 0x0e, 0xec, 0x67, 0x9d,
			  0x92, 0x7e, 0x38, 0x5b, 0x5d, 0xa7, 0xd4, 0xd3, 0xc1, 0xa5, 0x91, 0x69, 0xb4, 0x63, 0x0b, 0x87, 0x4a,
			  0x1d, 0x96, 0x9e, 0x45, 0xd1, 0xfe, 0x37, 0x82, 0x08, 0x9f, 0x43, 0x85, 0x02, 0x49, 0x55, 0x09, 0x3b,
			  0x30, 0x8e, 0x19, 0x64, 0xd3, 0x07, 0x91, 0x52, 0x71, 0xaa, 0x88, 0x6c, 0x3d, 0x9b, 0x64, 0xd8, 0x46,
			  0xc8, 0x8c, 0xa1, 0x34, 0x1f, 0xd2, 0xf7, 0x2b, 0x76, 0x67, 0x9d, 0x4f, 0x25, 0x8f, 0x64, 0x7b, 0xc0,
			  0x48, 0x20, 0xe4, 0x27, 0x76, 0xc9, 0xec, 0x0d, 0x01, 0x46, 0x46, 0x52, 0x76, 0x3a, 0x49, 0xd8, 0x22,
			  0xc9, 0xd2, 0x5b, 0x60, 0x39, 0x03, 0xeb, 0xd6, 0x33, 0x89, 0x52, 0x25, 0x9b, 0x83, 0xa7, 0x40, 0xa4,
			  0x20, 0xd6, 0x9d, 0x23, 0xae, 0xbb, 0xdf, 0x06, 0xa9, 0x2d, 0x88, 0xa4, 0x6f, 0xfc, 0xd8, 0xd8, 0x1a,
			  0x47, 0xb6, 0xec, 0x99, 0xb6, 0xce, 0xa0, 0x48, 0x9c, 0xc8, 0x3e, 0xf1, 0x57, 0x57, 0xc4, 0x05, 0x3d,
			  0x53, 0x84, 0x46, 0xf2, 0xe6, 0xb9, 0xeb, 0xa1, 0x2c, 0xe4, 0x96, 0x9b, 0x8d, 0x6d, 0xf9, 0xb3, 0xef,
			  0x57, 0x4b, 0x7d, 0x40, 0x13, 0x41, 0xc2, 0xf5, 0x55, 0xa0, 0x0f, 0x02, 0x91, 0x64, 0xe5, 0xd3, 0x87,
			  0x28, 0x2c, 0x0c, 0x87, 0x91, 0xba, 0x8c, 0x69, 0x81, 0x62, 0x48, 0xe2, 0xe5, 0x44, 0xa9, 0xc1, 0x2b,
			  0x7a, 0xeb, 0xa6, 0x29, 0xfd, 0xee, 0xa2, 0xe1, 0x11, 0x65, 0x5e, 0x44, 0xb9, 0xc2, 0x15, 0x92, 0x4c,
			  0x54, 0x55, 0xea, 0xa4, 0xab, 0x32, 0xae, 0xa1, 0xd9, 0xce, 0xf1, 0xd8, 0x6e, 0x8a, 0xcf, 0x6b, 0x0f,
			  0xf4, 0xdc, 0xab, 0xaf, 0x4f, 0x0e, 0x2d, 0x9a, 0xe6, 0x5c, 0x8b, 0xb1, 0x06, 0x5e, 0x04, 0x18, 0xff,
			  0x12, 0xd4, 0x62, 0x69, 0x30, 0x31, 0x59, 0x38, 0xbf, 0xe0, 0x0a, 0x8d, 0x03, 0xe8, 0xe7, 0x0e, 0x9d,
			  0xea, 0x9d, 0xc9, 0xff, 0x74, 0x85, 0x4c, 0xbb, 0x4d, 0xbd, 0xf7, 0x00, 0xa6, 0x2e, 0x77, 0xb2, 0x6e,
			  0x50, 0xb1, 0x3e, 0x2d, 0x39, 0x60, 0xc9, 0x13, 0x36, 0x0c, 0x84, 0xc8, 0x7e, 0x80, 0x1e, 0xd3, 0xdf,
			  0x3d, 0xb0, 0xe2, 0x76, 0x04, 0x50, 0x8c, 0xb7, 0x30, 0xc5, 0xa0, 0x52, 0xc0, 0x68, 0xab, 0xe5, 0x82,
			  0x6b, 0x01, 0xbe, 0x9f, 0x62, 0xe3, 0x3b, 0x9a, 0xf8, 0xed, 0xb6, 0x66, 0x7c, 0x57, 0xcb, 0x1a, 0xa8,
			  0x79, 0x74, 0x3b, 0x77, 0xa7, 0x43, 0x2f, 0x75, 0xfe, 0x3a, 0xe2, 0x11, 0xf9, 0x6a, 0xf4, 0x1a, 0xde,
			  0xf1, 0xe1, 0xc5, 0x07, 0x25, 0x6f, 0xe5, 0xfa, 0x2b, 0xcc, 0xab, 0xe5, 0x2c, 0xf8, 0x21, 0x6d, 0x34,
			  0x10, 0xe6, 0x37, 0x85, 0x06, 0xd4, 0x27, 0x34, 0x34, 0x58, 0x33, 0x2d, 0x15, 0x3a, 0x77, 0xa1, 0x62,
			  0xc4, 0xc5, 0xf1, 0x8d, 0x9f, 0x31, 0xb0, 0xc1, 0x42, 0x88, 0x0c, 0xad, 0x22, 0x29, 0x98, 0x17, 0x20,
			  0x61, 0x5a, 0xb2, 0x6b, 0x7c, 0x13, 0x44, 0x2e, 0x43, 0x17, 0x8a, 0xad, 0xee, 0x43, 0x65, 0x10, 0xc9,
			  0x1b, 0xc9, 0xd5, 0xd7, 0x35, 0xeb, 0x94, 0x53, 0xcf, 0x39, 0xce, 0xf5, 0x12, 0x0e, 0x28, 0x60, 0x37,
			  0x75, 0xf0, 0x48, 0x3f, 0x01, 0xc3, 0xc4, 0x8b, 0x5b, 0x06, 0x0c, 0xa7, 0xf3, 0xa5, 0x4d, 0x7c, 0x7c,
			  0x99, 0xa4, 0x81, 0xc9, 0x30, 0x81, 0xc6, 0xa0, 0x03, 0x02, 0x01, 0x17, 0xa2, 0x81, 0xbe, 0x04, 0x81,
			  0xbb, 0x03, 0xab, 0x65, 0x67, 0x60, 0xa3, 0x51, 0x2f, 0xec, 0xc7, 0x03, 0x2d, 0xa8, 0xb2, 0x01, 0x46,
			  0x59, 0xf0, 0xfb, 0x34, 0xeb, 0x76, 0xb4, 0x61, 0xe4, 0x04, 0x4d, 0xa2, 0x4d, 0x16, 0xd4, 0x58, 0xe3,
			  0xe1, 0xc5, 0x89, 0x19, 0xc7, 0x4c, 0x4c, 0x07, 0x20, 0xaa, 0xfb, 0x87, 0xa9, 0x48, 0x15, 0x23, 0x72,
			  0xa2, 0x48, 0x3a, 0x4d, 0x1a, 0xe9, 0xb9, 0x5b, 0x85, 0x8a, 0x52, 0xab, 0xaa, 0x94, 0xe7, 0xaa, 0x64,
			  0x1a, 0x8b, 0x99, 0x7d, 0x7e, 0x6c, 0x6e, 0x57, 0x0b, 0x59, 0x08, 0xcc, 0x54, 0x91, 0x55, 0xf5, 0xe6,
			  0xf1, 0x10, 0xc9, 0x8d, 0x64, 0x89, 0x78, 0x72, 0x7a, 0xba, 0xe3, 0x92, 0x1d, 0xa5, 0x2a, 0x4c, 0x1f,
			  0xd7, 0x6b, 0xeb, 0x12, 0x1b, 0xf3, 0x39, 0x6b, 0xe8, 0xf9, 0x8e, 0x4a, 0xcf, 0x1e, 0xbf, 0xc3, 0xb6,
			  0xfb, 0x7a, 0x13, 0x54, 0xc1, 0x21, 0x87, 0x3e, 0x59, 0x18, 0x5d, 0xb9, 0x00, 0x30, 0x08, 0x4d, 0x97,
			  0x86, 0x47, 0x98, 0xd7, 0x9e, 0xb9, 0xdf, 0x30, 0x75, 0x6c, 0xa1, 0xfa, 0xa7, 0xa8, 0x08, 0x80, 0xf7,
			  0x4f, 0x7d, 0x93, 0x64, 0x2d, 0x9c, 0xeb, 0x5e, 0x01, 0x28, 0xce, 0xd6, 0xab, 0x09, 0x6a, 0x4f, 0x01,
			  0x5e, 0x5a, 0x03, 0x2b, 0x42, 0x70, 0x23, 0x1e, 0x7f, 0xf1, 0xbc, 0xd0, 0x87, 0xe8, 0xb5, 0x27, 0x02,
			  0x7d }
		};
		pcpp::LdapBindRequestLayer bindRequestLayer(2, 3, "", saslAuthentication);

		auto expectedBindRequestLayer = bindRequestPacket.getLayerOfType<pcpp::LdapBindRequestLayer>();
		PTF_ASSERT_NOT_NULL(expectedBindRequestLayer);

		PTF_ASSERT_EQUAL(bindRequestLayer.getLdapOperationAsn1Record()->getSubRecords().size(),
		                 expectedBindRequestLayer->getLdapOperationAsn1Record()->getSubRecords().size());
		PTF_ASSERT_TRUE(std::equal(
		    bindRequestLayer.getLdapOperationAsn1Record()->getSubRecords().begin(),
		    bindRequestLayer.getLdapOperationAsn1Record()->getSubRecords().end(),
		    expectedBindRequestLayer->getLdapOperationAsn1Record()->getSubRecords().begin(),
		    [](pcpp::Asn1Record* elem1, pcpp::Asn1Record* elem2) { return elem1->encode() == elem2->encode(); }));
	}

	// BindResponse with server sasl credentials
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_bind_response1.dat");
		pcpp::Packet bindResponsePacket(rawPacket1.get());

		std::vector<uint8_t> serverSaslCredentials = {
			0xa1, 0x81, 0xa1, 0x30, 0x81, 0x9e, 0xa0, 0x03, 0x0a, 0x01, 0x00, 0xa1, 0x0b, 0x06, 0x09, 0x2a, 0x86,
			0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02, 0xa2, 0x81, 0x89, 0x04, 0x81, 0x86, 0x60, 0x81, 0x83, 0x06,
			0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x02, 0x00, 0x6f, 0x74, 0x30, 0x72, 0xa0,
			0x03, 0x02, 0x01, 0x05, 0xa1, 0x03, 0x02, 0x01, 0x0f, 0xa2, 0x66, 0x30, 0x64, 0xa0, 0x03, 0x02, 0x01,
			0x17, 0xa2, 0x5d, 0x04, 0x5b, 0x4a, 0x9f, 0x10, 0xab, 0x89, 0x96, 0xfa, 0x43, 0xf2, 0xfb, 0x40, 0x92,
			0xa7, 0x6c, 0xc3, 0xfa, 0x6c, 0x1f, 0x00, 0x11, 0x67, 0xfa, 0xc9, 0x04, 0xda, 0xb0, 0x67, 0xf5, 0xf2,
			0xda, 0x59, 0xa7, 0x54, 0x90, 0x57, 0xbd, 0x3e, 0xb4, 0x6c, 0xb4, 0x67, 0xfd, 0x3b, 0x01, 0xd7, 0x3f,
			0x50, 0x51, 0xaa, 0x63, 0x2e, 0xd8, 0xd6, 0xa6, 0xe5, 0x81, 0xbb, 0xab, 0x17, 0x80, 0xfa, 0xab, 0xac,
			0x51, 0x52, 0x84, 0x13, 0x9c, 0xfb, 0x44, 0xc2, 0x04, 0xae, 0x1e, 0xc2, 0x5a, 0x2d, 0x58, 0x90, 0x9d,
			0x22, 0xff, 0x52, 0x34, 0x9e, 0x6d, 0x2e, 0x4d, 0x83, 0x5b, 0x98
		};

		pcpp::LdapBindResponseLayer bindResponseLayer(215, pcpp::LdapResultCode::Success, "", "", {},
		                                              serverSaslCredentials);

		auto expectedBindResponseLayer = bindResponsePacket.getLayerOfType<pcpp::LdapBindResponseLayer>();
		PTF_ASSERT_NOT_NULL(expectedBindResponseLayer);

		PTF_ASSERT_EQUAL(bindResponseLayer.getLdapOperationAsn1Record()->getSubRecords().size(),
		                 expectedBindResponseLayer->getLdapOperationAsn1Record()->getSubRecords().size());

		for (int i = 0; i < 3; i++)
		{
			PTF_ASSERT_EQUAL(
			    bindResponseLayer.getLdapOperationAsn1Record()->getSubRecords().at(i)->toString(),
			    expectedBindResponseLayer->getLdapOperationAsn1Record()->getSubRecords().at(i)->toString());
		}

		auto actualServerSaslCredentialsRecord =
		    bindResponseLayer.getLdapOperationAsn1Record()->getSubRecords().at(3)->castAs<pcpp::Asn1GenericRecord>();
		// clang-format off
		auto expectedServerSaslCredentialsRecord = expectedBindResponseLayer->getLdapOperationAsn1Record()->getSubRecords().at(3)->castAs<pcpp::Asn1GenericRecord>();
		// clang-format on
		PTF_ASSERT_BUF_COMPARE(actualServerSaslCredentialsRecord->getValue(),
		                       expectedServerSaslCredentialsRecord->getValue(),
		                       expectedServerSaslCredentialsRecord->getValueLength())
	}

	// BindResponse without server sasl credentials
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_bind_response2.dat");
		pcpp::Packet bindResponsePacket(rawPacket1.get());

		pcpp::LdapBindResponseLayer bindResponseLayer(2, pcpp::LdapResultCode::Success, "", "");

		auto expectedBindResponseLayer = bindResponsePacket.getLayerOfType<pcpp::LdapBindResponseLayer>();
		PTF_ASSERT_NOT_NULL(expectedBindResponseLayer);

		PTF_ASSERT_EQUAL(bindResponseLayer.getLdapOperationAsn1Record()->getSubRecords().size(),
		                 expectedBindResponseLayer->getLdapOperationAsn1Record()->getSubRecords().size());
		PTF_ASSERT_TRUE(std::equal(
		    bindResponseLayer.getLdapOperationAsn1Record()->getSubRecords().begin(),
		    bindResponseLayer.getLdapOperationAsn1Record()->getSubRecords().end(),
		    expectedBindResponseLayer->getLdapOperationAsn1Record()->getSubRecords().begin(),
		    [](pcpp::Asn1Record* elem1, pcpp::Asn1Record* elem2) { return elem1->encode() == elem2->encode(); }));
	}

	// UnbindRequest
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_unbind_request.dat");
		pcpp::Packet unbindRequestPacket(rawPacket1.get());

		pcpp::LdapUnbindRequestLayer unbindRequestLayer(3);

		auto expectedUnbindRequestLayer = unbindRequestPacket.getLayerOfType<pcpp::LdapUnbindRequestLayer>();
		PTF_ASSERT_NOT_NULL(expectedUnbindRequestLayer);

		PTF_ASSERT_BUF_COMPARE(unbindRequestLayer.getData(), expectedUnbindRequestLayer->getData(),
		                       expectedUnbindRequestLayer->getDataLen());
	}

	// SearchRequest
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_search_request2.dat");
		pcpp::Packet searchRequestPacket(rawPacket1.get());

		pcpp::Asn1OctetStringRecord filterSubRecord1("objectClass");
		pcpp::Asn1OctetStringRecord filterSubRecord2("subschema");
		pcpp::Asn1ConstructedRecord filterRecord(pcpp::Asn1TagClass::ContextSpecific, 3,
		                                         { &filterSubRecord1, &filterSubRecord2 });

		std::vector<std::string> attributes = { "objectClasses",
			                                    "attributeTypes",
			                                    "ldapSyntaxes",
			                                    "matchingRules",
			                                    "matchingRuleUse",
			                                    "dITContentRules",
			                                    "dITStructureRules",
			                                    "nameForms",
			                                    "createTimestamp",
			                                    "modifyTimestamp",
			                                    "*",
			                                    "+" };

		pcpp::LdapSearchRequestLayer searchRequestLayer(
		    9, "cn=schema", pcpp::LdapSearchRequestLayer::SearchRequestScope::BaseObject,
		    pcpp::LdapSearchRequestLayer::DerefAliases::DerefAlways, 0, 0, false, &filterRecord, attributes);

		auto expectedSearchRequestLayer = searchRequestPacket.getLayerOfType<pcpp::LdapSearchRequestLayer>();
		PTF_ASSERT_NOT_NULL(expectedSearchRequestLayer);

		PTF_ASSERT_BUF_COMPARE(searchRequestLayer.getData(), expectedSearchRequestLayer->getData(),
		                       expectedSearchRequestLayer->getDataLen());
	}

	// SearchResultEntry
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_search_result_entry.dat");
		pcpp::Packet searchResultEntryPacket(rawPacket1.get());

		// clang-format off
		std::vector<pcpp::LdapAttribute> attributes = {
			{ "objectclass", { "inetOrgPerson", "organizationalPerson", "person", "top" } },
			{ "sn",          { "Young" }                                                },
			{ "cn",          { "b.smith" }                                              },
			{ "givenname",   { "Beatrix" }                                              }
		};
		// clang-format on

		pcpp::LdapSearchResultEntryLayer searchResultEntryLayer(
		    16, "cn=b.smith,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org", attributes);

		auto expectedSearchResultEntryLayer =
		    searchResultEntryPacket.getLayerOfType<pcpp::LdapSearchResultEntryLayer>();
		PTF_ASSERT_NOT_NULL(expectedSearchResultEntryLayer);

		PTF_ASSERT_BUF_COMPARE(searchResultEntryLayer.getData(), expectedSearchResultEntryLayer->getData(),
		                       expectedSearchResultEntryLayer->getDataLen());
	}

	// LdapSearchResultDoneLayer
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_search_result_done.dat");
		pcpp::Packet searchResultDonePacket(rawPacket1.get());

		pcpp::LdapSearchResultDoneLayer searchResultDoneLayer(8, pcpp::LdapResultCode::Success, "", "");

		auto expectedSearchResultDoneLayer = searchResultDonePacket.getLayerOfType<pcpp::LdapSearchResultDoneLayer>();
		PTF_ASSERT_NOT_NULL(expectedSearchResultDoneLayer);

		PTF_ASSERT_BUF_COMPARE(searchResultDoneLayer.getData(), expectedSearchResultDoneLayer->getData(),
		                       expectedSearchResultDoneLayer->getDataLen());
	}

	// LdapModifyResponseLayer
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_modify_response.dat");
		pcpp::Packet modifyResponsePacket(rawPacket1.get());

		pcpp::LdapModifyResponseLayer modifyResponseLayer(14, pcpp::LdapResultCode::NoSuchObject, "", "");

		auto expectedModifyResponseLayer = modifyResponsePacket.getLayerOfType<pcpp::LdapModifyResponseLayer>();
		PTF_ASSERT_NOT_NULL(expectedModifyResponseLayer);

		PTF_ASSERT_BUF_COMPARE(modifyResponseLayer.getData(), expectedModifyResponseLayer->getData(),
		                       expectedModifyResponseLayer->getDataLen());
	}

	// LdapAddResponseLayer
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_add_response.dat");
		pcpp::Packet addResponsePacket(rawPacket1.get());

		pcpp::LdapAddResponseLayer addResponseLayer(27, pcpp::LdapResultCode::Success, "", "");

		auto expectedAddResponseLayer = addResponsePacket.getLayerOfType<pcpp::LdapAddResponseLayer>();
		PTF_ASSERT_NOT_NULL(expectedAddResponseLayer);

		PTF_ASSERT_BUF_COMPARE(addResponseLayer.getData(), expectedAddResponseLayer->getData(),
		                       expectedAddResponseLayer->getDataLen());
	}

	// LdapDeleteResponseLayer
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_delete_response.dat");
		pcpp::Packet deleteResponsePacket(rawPacket1.get());

		std::vector<std::string> referral = { "ldap://ldap.example.com/dc=example,dc=com",
			                                  "ldap://ldap.example.com/dc=example,dc=com?objectClass?one" };

		pcpp::LdapDeleteResponseLayer deleteResponseLayer(27, pcpp::LdapResultCode::NoSuchObject,
		                                                  "ou=People,dc=example,dc=com",
		                                                  "LDAP: error code 32 - No such object", referral);

		auto expectedDeleteResponseLayer = deleteResponsePacket.getLayerOfType<pcpp::LdapDeleteResponseLayer>();
		PTF_ASSERT_NOT_NULL(expectedDeleteResponseLayer);

		PTF_ASSERT_BUF_COMPARE(deleteResponseLayer.getData(), expectedDeleteResponseLayer->getData(),
		                       expectedDeleteResponseLayer->getDataLen());
	}

	// LdapModifyDNResponseLayer
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_modify_dn_response.dat");
		pcpp::Packet modifyDNResponsePacket(rawPacket1.get());

		pcpp::LdapModifyDNResponseLayer modifyDNResponseLayer(15, pcpp::LdapResultCode::NoSuchObject,
		                                                      "ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org", "");

		auto expectedModifyDNResponseLayer = modifyDNResponsePacket.getLayerOfType<pcpp::LdapModifyDNResponseLayer>();
		PTF_ASSERT_NOT_NULL(expectedModifyDNResponseLayer);

		PTF_ASSERT_BUF_COMPARE(modifyDNResponseLayer.getData(), expectedModifyDNResponseLayer->getData(),
		                       expectedModifyDNResponseLayer->getDataLen());
	}

	// LdapCompareResponseLayer
	{
		auto rawPacket1 = createPacketFromHexResource("PacketExamples/ldap_compare_response.dat");
		pcpp::Packet compareResponsePacket(rawPacket1.get());

		pcpp::LdapCompareResponseLayer compareResponseLayer(28, pcpp::LdapResultCode::CompareFalse, "", "");

		auto expectedCompareResponseLayer = compareResponsePacket.getLayerOfType<pcpp::LdapCompareResponseLayer>();
		PTF_ASSERT_NOT_NULL(expectedCompareResponseLayer);

		PTF_ASSERT_BUF_COMPARE(compareResponseLayer.getData(), expectedCompareResponseLayer->getData(),
		                       expectedCompareResponseLayer->getDataLen());
	}
}  // LdapCreationTest
